#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
布局画布模块
提供CEGUI布局编辑器的布局预览和编辑功能
"""

import os
import xml.etree.ElementTree as ET
from PyQt5.QtWidgets import QWidget, QMessageBox
from PyQt5.QtCore import Qt, QRect, QPoint, QSize, pyqtSignal
from PyQt5.QtGui import QPainter, QColor, QPen, QPixmap, QImage, QFont, QBrush

from .layout_canvas_drawing import LayoutCanvasDrawing
from .layout_canvas_handlers import LayoutCanvasHandlers
from .layout_canvas_utils import LayoutCanvasUtils

class LayoutCanvas(QWidget):
    """布局画布部件"""
    
    # 添加新的信号
    layout_converted = pyqtSignal()
    
    # 添加元素选择信号
    element_selected = pyqtSignal(object)
    
    def __init__(self, parent=None):
        super(LayoutCanvas, self).__init__(parent)
        self.root = None
        self.selected_element = None
        self.main_window = parent
        self.resolution = (800, 600)  # 默认分辨率
        self.scale_factor = 1.0  # 缩放因子
        self.base_resolution = (800, 600)  # 基准分辨率
        self.final_render_mode = False  # 最终渲染模式标志
        # 添加拖拽相关变量
        self.dragging = False
        self.drag_start_pos = None
        self.drag_element = None
        self.drag_start_rect = None
        self.snap_threshold = 10  # 吸附阈值，单位像素
        # 添加性能优化变量
        self.last_update_time = 0  # 上次更新时间
        self.update_interval = 20  # 更新间隔(ms)，提高到约50fps(原来16ms约60fps)
        self.cached_parent_rect = None  # 缓存父元素矩形
        # 添加图像缓存
        self.image_cache = {}  # 格式: {"set:imageset_name image:image_name": QPixmap}
        # 添加隐藏元素跟踪
        self.hidden_elements = set()  # 存储被隐藏元素的集合
        
        # 添加坐标模式
        self.coordinate_mode = 'relative'  # 'relative' 或 'absolute'
        
        # 添加大小调整相关变量
        self.resizing = False  # 是否正在调整大小
        self.resize_handle = None  # 当前激活的调整手柄
        self.resize_element = None  # 正在调整大小的元素
        self.resize_start_pos = None  # 开始调整大小时鼠标位置
        self.resize_start_rect = None  # 开始调整大小前元素的矩形
        self.resize_handles_size = 12  # 调整手柄大小
        self.resize_handle_positions = {
            'top_left': 0,
            'top': 1,
            'top_right': 2,
            'right': 3,
            'bottom_right': 4,
            'bottom': 5,
            'bottom_left': 6,
            'left': 7
        }
        self.alt_pressed = False  # Alt键是否按下(用于保持比例)
        
        # 添加平移相关变量
        self.panning = False  # 是否正在平移
        self.pan_start_pos = None  # 开始平移时的鼠标位置
        self.pan_offset = QPoint(0, 0)  # 平移偏移量
        
        # 添加鼠标位置跟踪
        self.last_mouse_pos = None  # 记录鼠标在布局中的位置
        
        # 添加撤销功能相关变量
        self.undo_stack = []  # 撤销栈
        self.max_undo_steps = 50  # 最大撤销步数
        self.ctrl_pressed = False  # Ctrl键是否按下
        
        # 设置仅点击选择元素的标志
        self.click_select_only = True  # 只能通过点击选中元素，拖动时不会选中其他元素
        
        # 添加跟踪鼠标选中的变量
        self.potential_select_element = None  # 潜在要选中的元素（鼠标按下时）
        self.mouse_press_pos = None  # 鼠标按下的位置
        self.drag_threshold = 5  # 拖动阈值，小于这个值视为点击而不是拖动
        
        self.init_ui()
        
        # 初始化辅助类
        self.drawing = LayoutCanvasDrawing(self)
        self.handlers = LayoutCanvasHandlers(self)
        self.utils = LayoutCanvasUtils(self)
    
    def init_ui(self):
        """初始化UI"""
        # 设置固定大小
        self.setMinimumSize(800, 600)
        
        # 设置焦点策略
        self.setFocusPolicy(Qt.StrongFocus)
        
        # 设置背景
        self.setStyleSheet("background-color: #333333;")
    
    def set_layout_root(self, root):
        """设置布局根元素"""
        self.root = root
        self.selected_element = None
        # 清空图像缓存，确保新布局能够正确加载图像
        self.image_cache.clear()
        # 清空隐藏元素集合
        self.hidden_elements.clear()
        self.update()
    
    def get_layout_root(self):
        """获取布局根元素
        
        返回:
            Element: 布局根元素，如果没有加载布局则返回None
        """
        # 添加类型检查，防止返回错误类型
        if self.root is not None and not isinstance(self.root, ET.Element):
            print(f"警告: 布局根元素类型非预期: {type(self.root)}")
            # 如果是字符串，尝试解析为XML元素
            if isinstance(self.root, str):
                try:
                    print("尝试将字符串解析为XML元素")
                    self.root = ET.fromstring(self.root)
                    print("解析成功")
                except Exception as e:
                    print(f"解析字符串为XML元素失败: {e}")
                    return None
        return self.root
    
    def set_selected_element(self, element):
        """设置选中的元素"""
        if self.selected_element != element:
            self.selected_element = element
            # 触发元素选择信号
            self.element_selected.emit(element)
            # 重绘画布
            self.update()
            # 重置光标
            if element is None:
                self.setCursor(Qt.ArrowCursor)
    
    def set_final_render_mode(self, enabled):
        """设置是否使用最终渲染模式"""
        self.final_render_mode = enabled
        self.update()
        
    def get_final_render_mode(self):
        """获取当前渲染模式状态"""
        return self.final_render_mode
    
    def set_resolution(self, width, height):
        """设置预览分辨率"""
        # 清理部分图像缓存，避免占用过多内存
        self.clear_image_cache()
        
        self.resolution = (width, height)
        
        # 计算缩放因子
        canvas_width = self.width()
        canvas_height = self.height()
        
        # 如果画布比例与目标分辨率比例不同，需要调整
        canvas_ratio = canvas_width / canvas_height
        target_ratio = width / height
        
        if canvas_ratio > target_ratio:
            # 画布更宽，以高度为准
            self.scale_factor = canvas_height / height
        else:
            # 画布更高，以宽度为准
            self.scale_factor = canvas_width / width
        
        self.update()
        return self.scale_factor
    
    def get_resolution(self):
        """获取当前预览分辨率"""
        return self.resolution
    
    def paintEvent(self, event):
        """绘制事件"""
        self.drawing.paint(event)
    
    def resizeEvent(self, event):
        """窗口大小改变事件"""
        super().resizeEvent(event)
        # 重新计算缩放因子
        self.set_resolution(self.resolution[0], self.resolution[1])
    
    def mousePressEvent(self, event):
        """鼠标按下事件"""
        self.handlers.handle_mouse_press(event)
    
    def mouseMoveEvent(self, event):
        """鼠标移动事件"""
        self.handlers.handle_mouse_move(event)
    
    def mouseReleaseEvent(self, event):
        """鼠标释放事件"""
        self.handlers.handle_mouse_release(event)
    
    def keyPressEvent(self, event):
        """处理键盘按键事件"""
        # 确保有选中的元素
        if not self.selected_element:
            return super().keyPressEvent(event)
            
        # 获取按键和修饰键
        key = event.key()
        ctrl_pressed = event.modifiers() & Qt.ControlModifier
        
        # 根据坐标模式计算移动步长
        if self.coordinate_mode == 'absolute':
            # 绝对像素模式：直接使用1像素
            pixel_x_step = 1.0 / self.resolution[0]
            pixel_y_step = 1.0 / self.resolution[1]
            step_description = "1像素"
        else:
            # 相对坐标模式：使用更小的步长，约相当于1/100的屏幕
            pixel_x_step = 0.01
            pixel_y_step = 0.01
            step_description = "1%"
        
        # 处理箭头键
        if key in (Qt.Key_Left, Qt.Key_Right, Qt.Key_Up, Qt.Key_Down):
            # 获取当前UnifiedAreaRect
            area_rect = None
            for prop in self.selected_element.findall('Property'):
                if prop.get('Name') == 'UnifiedAreaRect':
                    area_rect = prop.get('Value')
                    break
                    
            if not area_rect:
                return super().keyPressEvent(event)
                
            # 解析当前坐标
            try:
                x1, y1, x2, y2 = self.utils.parse_unified_area_rect_string(area_rect)
                
                # 根据按键和修饰键决定操作
                if ctrl_pressed:
                    # Ctrl+箭头键：调整大小
                    if key == Qt.Key_Left:
                        # 减小宽度 (增加左边界)
                        x1 += pixel_x_step
                    elif key == Qt.Key_Right:
                        # 增加宽度 (增加右边界)
                        x2 += pixel_x_step
                    elif key == Qt.Key_Up:
                        # 减小高度 (增加上边界)
                        y1 += pixel_y_step
                    elif key == Qt.Key_Down:
                        # 增加高度 (增加下边界)
                        y2 += pixel_y_step
                else:
                    # 箭头键：移动位置
                    if key == Qt.Key_Left:
                        # 向左移动
                        x1 -= pixel_x_step
                        x2 -= pixel_x_step
                    elif key == Qt.Key_Right:
                        # 向右移动
                        x1 += pixel_x_step
                        x2 += pixel_x_step
                    elif key == Qt.Key_Up:
                        # 向上移动
                        y1 -= pixel_y_step
                        y2 -= pixel_y_step
                    elif key == Qt.Key_Down:
                        # 向下移动
                        y1 += pixel_y_step
                        y2 += pixel_y_step
                
                # 确保坐标有效
                x1 = max(0, min(x1, 1))
                y1 = max(0, min(y1, 1))
                x2 = max(0, min(x2, 1))
                y2 = max(0, min(y2, 1))
                
                # 确保x1 < x2, y1 < y2
                if x1 >= x2: x1 = x2 - pixel_x_step
                if y1 >= y2: y1 = y2 - pixel_y_step
                
                # 更新UnifiedAreaRect
                new_area_rect = f"{{{{{x1:.6f},0}},{{{y1:.6f},0}},{{{x2:.6f},0}},{{{y2:.6f},0}}}}"
                
                # 更新元素属性
                for prop in self.selected_element.findall('Property'):
                    if prop.get('Name') == 'UnifiedAreaRect':
                        prop.set('Value', new_area_rect)
                        break
                
                # 更新UI
                self.update()
                
                # 标记布局为已修改
                if self.main_window:
                    self.main_window.is_layout_modified = True
                    self.main_window.update_window_title()
                    
                    # 更新属性编辑器
                    if self.main_window.property_editor.current_element == self.selected_element:
                        self.main_window.property_editor.update_properties()
                        
                    # 更新XML视图
                    if hasattr(self.main_window, 'tab_widget') and self.main_window.tab_widget.currentIndex() == 1:  # XML视图
                        self.main_window.update_xml_view()
                        
                    # 显示状态信息
                    op_type = "缩放" if ctrl_pressed else "移动"
                    direction = ""
                    if key == Qt.Key_Left: direction = "左"
                    elif key == Qt.Key_Right: direction = "右"
                    elif key == Qt.Key_Up: direction = "上"
                    elif key == Qt.Key_Down: direction = "下"
                    
                    element_name = self.selected_element.get('Name', '未命名')
                    mode_text = "绝对像素" if self.coordinate_mode == 'absolute' else "相对坐标"
                    self.main_window.statusBar().showMessage(f'已{op_type}元素 "{element_name}" 向{direction}方向{step_description} ({mode_text}模式)')
                
                event.accept()
                return
                
            except Exception as e:
                print(f"键盘操作元素时出错: {e}")
                import traceback
                traceback.print_exc()
        
        super().keyPressEvent(event)
    
    def keyReleaseEvent(self, event):
        """键盘释放事件"""
        self.handlers.handle_key_release(event)
        
    def wheelEvent(self, event):
        """处理鼠标滚轮事件，实现缩放功能"""
        self.handlers.handle_wheel(event)
    
    def clear_image_cache(self, full_clear=False):
        """清理图像缓存
        
        参数:
            full_clear: 是否完全清空缓存，默认为False，只清理超过缓存大小限制的部分
        """
        # 如果缓存为空，无需清理
        if not self.image_cache:
            return
            
        # 缓存大小限制(数量)
        cache_limit = 100
        
        if full_clear:
            self.image_cache.clear()
        elif len(self.image_cache) > cache_limit:
            # 删除超出限制的部分
            keys_to_delete = list(self.image_cache.keys())[cache_limit:]
            for key in keys_to_delete:
                del self.image_cache[key]
    
    def set_element_hidden(self, element, hidden=True):
        """设置元素的隐藏状态
        
        参数:
            element: 要设置隐藏状态的元素
            hidden: 是否隐藏，True为隐藏，False为显示
            
        返回:
            bool: 设置后的隐藏状态
        """
        if hidden:
            self.hidden_elements.add(element)
        elif element in self.hidden_elements:
            self.hidden_elements.remove(element)
        
        # 更新画布
        self.update()
        
        return hidden
    
    def toggle_element_visibility(self, element):
        """切换元素的可见性
        
        参数:
            element: 要切换可见性的元素
            
        返回:
            bool: 切换后的隐藏状态，True为隐藏，False为显示
        """
        # 如果元素已经在隐藏列表中，则显示它
        if element in self.hidden_elements:
            return self.set_element_hidden(element, False)
        # 否则隐藏它
        else:
            return self.set_element_hidden(element, True)
            
    def is_element_hidden(self, element):
        """检查元素是否被隐藏
        
        参数:
            element: 要检查的元素
            
        返回:
            bool: 元素是否被隐藏
        """
        return element in self.hidden_elements
        
    def get_click_select_only(self):
        """获取是否只能通过点击选中元素
        
        返回:
            bool: 是否只能通过点击选中元素
        """
        return self.click_select_only
        
    def set_click_select_only(self, value):
        """设置是否只能通过点击选中元素
        
        参数:
            value: 是否只能通过点击选中元素
            
        返回:
            bool: 设置后的值
        """
        self.click_select_only = bool(value)
        return self.click_select_only
        
    def set_coordinate_mode(self, mode):
        """设置坐标模式
        
        参数:
            mode: 坐标模式，'relative' 或 'absolute'
        """
        if mode in ['relative', 'absolute']:
            self.coordinate_mode = mode
            
    def get_coordinate_mode(self):
        """获取当前坐标模式
        
        返回:
            str: 当前坐标模式
        """
        return self.coordinate_mode 